package com.ece.pfe_rover_pvt_ines_ece_application.view;

import java.util.Arrays;
import java.util.List;

import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.ece.pfe_rover_pvt_ines_ece_application.PFE_ROVER_PVT_INES_ECE_Application;
import com.ece.pfe_rover_pvt_ines_ece_application.R;
import com.ece.pfe_rover_pvt_ines_ece_application.model.Measurements;
import com.parse.FindCallback;
import com.parse.ParseAnonymousUtils;
import com.parse.ParseException;
import com.parse.ParseObject;
import com.parse.ParseQuery;
import com.parse.ParseQueryAdapter;
import com.parse.ParseUser;
import com.parse.SaveCallback;
//import com.parse.offlinetodos.R;
import com.parse.ui.ParseLoginActivity;
import com.parse.ui.ParseLoginBuilder;

/**
 * Main view of the application
 * First action: ask for authentication
 * Then shows the available measurements
 * @author mathieubakrim
 *
 */
public class MeasureActivity extends Activity {
	
	public boolean DEBUG_MODE = PFE_ROVER_PVT_INES_ECE_Application.DEBUG;
	private static final int LOGIN_ACTIVITY_CODE = 100;
	private static final int EDIT_ACTIVITY_CODE = 200;
	private static final boolean PUBLIC_READ_ACCESS = true;
	private static final boolean AUTHENTICATION_NEEDED = false;

	// Adapter for the Measurements Parse Query
	private ParseQueryAdapter<Measurements> MeasurementsListAdapter;
	
	private LayoutInflater inflater;
	private ListView MeasurementsListView;
	private LinearLayout noMeasurementssView;
	private TextView loggedInInfoView;

	/**
	 * OnCreate (Android method related to Activity class)
	 * Compose the view (layouts, buttons...)
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		
		if(DEBUG_MODE) System.out.println("---- Entering onCreate method...");
		
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_measurements_list);

		// Menu & subtitle
		ActionBar actionBar = getActionBar();
		actionBar.setDisplayHomeAsUpEnabled(true);
		actionBar.setSubtitle(R.string.subtitle_list);
		
		// Shows up authentication window
		if(AUTHENTICATION_NEEDED){
			Intent i = new Intent(this, ParseLoginActivity.class);
			startActivityForResult(i, LOGIN_ACTIVITY_CODE);	
		}
				
		// Set up the views
		MeasurementsListView = (ListView) findViewById(R.id.measurements_list_view);
		noMeasurementssView = (LinearLayout) findViewById(R.id.no_measurements_view);
		MeasurementsListView.setEmptyView(noMeasurementssView);
		loggedInInfoView = (TextView) findViewById(R.id.loggedin_info);

		// Set up the Parse query to use in the adapter
		ParseQueryAdapter.QueryFactory<Measurements> factory = new ParseQueryAdapter.QueryFactory<Measurements>() {
			public ParseQuery<Measurements> create() {
				ParseQuery<Measurements> query = Measurements.getQuery();
				query.orderByDescending("EntryId");
				query.fromLocalDatastore();
				return query;
			}
		};
		
		// Set up the adapter
		inflater = (LayoutInflater) this
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		MeasurementsListAdapter = new MeasurementsListAdapter(this, factory);

		// Attach the query adapter to the view
		ListView MeasurementsListView = (ListView) findViewById(R.id.measurements_list_view);
		MeasurementsListView.setAdapter(MeasurementsListAdapter);

		// Listener on list items (when you click on a measurement)
		// Retrieve the measurement & show its details in editview.
		MeasurementsListView.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				Measurements Measurements = MeasurementsListAdapter.getItem(position);
				openEditView(Measurements);
			}
		});
	}

	/**
	 * On resume (see Android LifeCycle)
	 */
	@Override
	protected void onResume() {
		
		if(DEBUG_MODE) System.out.println("---- Entering onResume method...");
		
		super.onResume();
		
		// Check if we have a real user
		if (ParseUser.getCurrentUser() != null && (!ParseAnonymousUtils.isLinked(ParseUser.getCurrentUser()))) {
			// Sync data to Parse
			//syncMeasurementssToParse();
			// Update the logged in label info
			updateLoggedInInfo();
		}
	}
	
	/**
	 * Notification to show who has logged in
	 */
	private void updateLoggedInInfo() {
		
		if(DEBUG_MODE) System.out.println("---- Entering updateLoggedInfo method...");
		
		if ((ParseUser.getCurrentUser() != null) && !ParseAnonymousUtils.isLinked(ParseUser.getCurrentUser())) {
			ParseUser currentUser = ParseUser.getCurrentUser();
			loggedInInfoView.setText(getString(R.string.logged_in,
					currentUser.getString("name")));
		} else {
			loggedInInfoView.setText(getString(R.string.not_logged_in));
		}
	}

	/**
	 * Retrieve a chosen measurement from the list & show its details through a new window
	 * @param Measurements
	 */
	private void openEditView(Measurements Measurements) {
		
		if(DEBUG_MODE) System.out.println("---- Entering openEditView method...");
		
		Intent i = new Intent(this, NewMeasurementsActivity.class);		
		i.putExtra("ID", Measurements.getUuidString());
		startActivityForResult(i, EDIT_ACTIVITY_CODE);
	}

	/**
	 * Retrieve the code (edit or login) from the popup views (LOGIN / Edit)
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		
		if(PFE_ROVER_PVT_INES_ECE_Application.DEBUG) System.out.println("---- Entering onActivityResult method...");
		
		super.onActivityResult(requestCode, resultCode, data);
		// An OK result means the pinned dataset changed or
		// log in was successful
		if (resultCode == RESULT_OK) {
			if (requestCode == EDIT_ACTIVITY_CODE) {
				// Coming back from the edit view, update the view
				MeasurementsListAdapter.loadObjects();
			} else if (requestCode == LOGIN_ACTIVITY_CODE) {
				// If the user is new, sync data to Parse,
				// else get the current list from Parse
				if (ParseUser.getCurrentUser().isNew()) {
					//syncMeasurementssToParse();
				} else {
					loadFromParse();
				}
			}
		}
	}

	/**
	 * OnCreateOptionsMenu (Android method related to Activity class)
	 * Inflate the menu
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		
		if(DEBUG_MODE) System.out.println("---- Entering inCreateOptionsMenu method...");						
		getMenuInflater().inflate(R.menu.admin_action, menu);
		getMenuInflater().inflate(R.menu.action_login, menu);
		getMenuInflater().inflate(R.menu.action_logout, menu);
		getMenuInflater().inflate(R.menu.activity_main_actions, menu);			
		
		return true;
	}

	/**
	 * onOptionsItemSelected (Android method related to Activity class)
	 * Start the activity related to a selected field in the menu
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		
		if(DEBUG_MODE) System.out.println("---- Entering onOptionsItemSelected method...");
		
		if (item.getItemId() == R.id.action_new && 
				(ParseUser.getCurrentUser().getObjectId().equals(PFE_ROVER_PVT_INES_ECE_Application.ADMIN_ID))) {
			// Make sure there's a valid user, anonymous
			// or regular
			if (ParseUser.getCurrentUser() != null) {
				startActivityForResult(new Intent(this, NewMeasurementsActivity.class),
						EDIT_ACTIVITY_CODE);
			}
		}else if (item.getItemId() == R.id.action_new){
			Toast.makeText(getApplicationContext(), "Only available for Admins", Toast.LENGTH_LONG).show();
		}

		if (item.getItemId() == R.id.action_sync) {
			syncMeasurementssToParse();
		}

		if(item.getItemId() == R.id.measurements_table)
			startActivity(new Intent(this.getBaseContext(),TableActivity.class));
		
		if(item.getItemId() == R.id.referentiel)
			startActivity(new Intent(this.getBaseContext(),ReferentielActivity.class));
		
		if(item.getItemId() == R.id.measurements_graphs)
			startActivity(new Intent(this.getBaseContext(),GraphsActivity.class));
			
		if (item.getItemId() == R.id.action_logout) {			 
			// Log out the current user
			ParseUser.logOut();
			// Create a new anonymous user
			ParseAnonymousUtils.logIn(null);
			// Update the logged in label info
			updateLoggedInInfo();
			// Clear the view
			MeasurementsListAdapter.clear();
			// Unpin all the current objects
			ParseObject
					.unpinAllInBackground(PFE_ROVER_PVT_INES_ECE_Application.MEASUREMENTS_GROUP_NAME);
			
			Intent intent = new Intent(this, MainActivity.class);
			intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
			this.startActivity(intent);
			
		}

		if (item.getItemId() == R.id.action_login) {
			invalidateOptionsMenu();
			ParseLoginBuilder builder = new ParseLoginBuilder(this);
			startActivityForResult(builder.build(), LOGIN_ACTIVITY_CODE);
		}

		return super.onOptionsItemSelected(item);
	}

	/**
	 * onPrepareOptionsMenu
	 */
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		
		if(DEBUG_MODE) System.out.println("---- Entering onPrepareOptopnsMenu method...");
		
		boolean realUser;
		super.onPrepareOptionsMenu(menu);
		if(ParseUser.getCurrentUser() != null){
			realUser = !ParseAnonymousUtils.isLinked(ParseUser
				.getCurrentUser());
		
			menu.findItem(R.id.action_login).setVisible(!realUser);
			menu.findItem(R.id.action_logout).setVisible(realUser);
			menu.findItem(R.id.action_new).setVisible(false);
			menu.findItem(R.id.action_sync).setVisible(false);
		}
		
		if((ParseUser.getCurrentUser() != null && (ParseUser.getCurrentUser().getObjectId()
				.equals(PFE_ROVER_PVT_INES_ECE_Application.ADMIN_ID)))) {
			menu.findItem(R.id.action_new).setVisible(true);
			menu.findItem(R.id.action_sync).setVisible(true);
		}
		
		//Functionality disabled
		menu.findItem(R.id.action_new).setVisible(false);
		
		menu.findItem(R.id.measurements_list).setVisible(false);
		
		return true;
	}

	/**
	 * Load local changes to Parse online server
	 */
	private void syncMeasurementssToParse() {
		
		if(DEBUG_MODE) System.out.println("---- Entering syncMeasurementsstoParse method...");
		
		// We could use saveEventually here, but we want to have some UI
		// around whether or not the draft has been saved to Parse
		ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo ni = cm.getActiveNetworkInfo();
		if ((ni != null) && (ni.isConnected())) {			
			if (!ParseAnonymousUtils.isLinked(ParseUser.getCurrentUser())) {
				// If we have a network connection and a current logged in user,
				// sync the
				// Measurements

				// In this app, local changes should overwrite content on the
				// server.	
				
				//TODO
				// check if entryId already exists in the database
				ParseQuery<Measurements> queryParse = ParseQuery.getQuery(Measurements.class);				
				queryParse.selectKeys(Arrays.asList("EntryId"));
				List<Measurements> result = null;
				try {
					result = queryParse.find();
				} catch (ParseException e) {
					if(DEBUG_MODE) System.out.println("Query has not found anything");
					e.printStackTrace();
				}
				
				//TODO
				//Retrieve measurements from local dataStore in addition or in place 
				//of from pin.
				ParseQuery<Measurements> query = Measurements.getQuery();
				query.fromPin(PFE_ROVER_PVT_INES_ECE_Application.MEASUREMENTS_GROUP_NAME);
				query.whereEqualTo("isDraft", true);
				query.whereNotContainedIn("EntryId", result);				
				query.findInBackground(new FindCallback<Measurements>() {					
					public void done(List<Measurements> Measurementss, ParseException e) {						
						if (e == null) {							
							if(DEBUG_MODE) System.out.println("SyncMeasurements local measurements size: "+Measurementss.size());
							for (final Measurements Measurements : Measurementss) {
								// Set is draft flag to false before
								// syncing to Parse								
								Measurements.setDraft(false);
								Measurements.getACL().setPublicReadAccess(PUBLIC_READ_ACCESS);
								Measurements.saveInBackground(new SaveCallback() {

									@Override
									public void done(ParseException e) {
										if (e == null) {
											// Let adapter know to update view
											if (!isFinishing()) {
												MeasurementsListAdapter
														.notifyDataSetChanged();	
												if(DEBUG_MODE) System.out.println("sync with parse success case");
											}
										} else {
											// Reset the is draft flag locally
											// to true
											Measurements.setDraft(true);	
											if(DEBUG_MODE) System.out.println("sync with parse false case");
										}
									}
								});
							}							
						} else {	
							Log.i("MeasurementsListActivity",
									"syncMeasurementssToParse: Error finding pinned Measurementss: "
											+ e.getMessage());
						}
					}
				});
			} else {
				// If we have a network connection but no logged in user, direct
				// the person to log in or sign up.
				ParseLoginBuilder builder = new ParseLoginBuilder(this);
				startActivityForResult(builder.build(), LOGIN_ACTIVITY_CODE);				
			}
		} else {
			// If there is no connection, let the user know the sync didn't
			// happen
			Toast.makeText(
					getApplicationContext(),
					"Your device appears to be offline. Some Measurementss may not have been synced to Parse.",
					Toast.LENGTH_LONG).show();
		}
	}

	/**
	 * Load data from PARSE Online database
	 */
	private void loadFromParse() {
		
		if(DEBUG_MODE) System.out.println("---- Entering loadFromParse method...");
		
		ParseQuery<Measurements> query = Measurements.getQuery();
		query.whereEqualTo("author", ParseUser.getCurrentUser());	
		query.findInBackground(new FindCallback<Measurements>() {
			public void done(List<Measurements> Measurementss, ParseException e) {
				if (e == null) {
					ParseObject.pinAllInBackground((List<Measurements>) Measurementss,
							new SaveCallback() {
								public void done(ParseException e) {
									if (e == null) {
										if (!isFinishing()) {
											MeasurementsListAdapter.loadObjects();
										}
									} else {
										Log.i("MeasurementsListActivity",
												"Error pinning Measurementss: "
														+ e.getMessage());
									}
								}
							});
				} else {
					Log.i("MeasurementsListActivity",
							"loadFromParse: Error finding pinned Measurementss: "
									+ e.getMessage());
				}
			}
		});
	}

	/**
	 * Handles the fetching of objects by page and displaying objects as views in a listView
	 * @author mathieubakrim
	 *
	 */
	private class MeasurementsListAdapter extends ParseQueryAdapter<Measurements> {

		public MeasurementsListAdapter(Context context,
				ParseQueryAdapter.QueryFactory<Measurements> queryFactory) {
			super(context, queryFactory);			
		}

		@Override
		public View getItemView(Measurements Measurements, View view, ViewGroup parent) {
			ViewHolder holder;
			if (view == null) {
				view = inflater.inflate(R.layout.list_item_measurements, parent, false);
				holder = new ViewHolder();
				holder.MeasurementsTitle = (TextView) view
						.findViewById(R.id.measurements_title);
				view.setTag(holder);
			} else {
				holder = (ViewHolder) view.getTag();
			}
			TextView MeasurementsTitle = holder.MeasurementsTitle;
			MeasurementsTitle.setText("Measurement - "+ Measurements.getEntryId());
			if (Measurements.isDraft()) {
				MeasurementsTitle.setTypeface(null, Typeface.ITALIC);
				MeasurementsTitle.append("- draft");
			} else {
				MeasurementsTitle.setTypeface(null, Typeface.NORMAL);
				MeasurementsTitle.append("- Saved");
			}
			return view;
		}
	}

	/**
	 * Allow to show the measurement title on the view
	 * @author mathieubakrim
	 *
	 */
	private static class ViewHolder {
		TextView MeasurementsTitle;
	}
}
